# -*- mode: python; coding: utf-8; -*-
##--------------------------------------------------------------------------##
##
## Copyright (C) 1998-2003 Markus Oberhumer <markus@oberhumer.com>
## Copyright (C) 2003 Mt. Hood Playing Card Co.
## Copyright (C) 2005-2010 Skomoroh <skomoroh@users.sourceforge.net>
## Copyright (C) 2010-2013 Jeremy Austin-Bardo <tjaustinbardo@gmail.com>
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##--------------------------------------------------------------------------##
__docformat__ = "restructuredtext en"

from ..packlib import info as cs
from .. import pilelib as stack
from ..gamelib import state
from .. import comparecards as cmp_cards
from ..utillib.misc import kwdefault
from ..pilelib import move as a_move


class LarasGame_Talon(stack.RedealTalon):
    """
    Init deal cards deal back on _talon_
      - 1 card when rank is position.
      - 1 card when rank is face card.
      - 2 card when rank is ACE.
      - 2 card after _row_ turn.

    Deal _reserve_ back to its old _row_ rank pile, then deal 1 card and its
    new _row_ rank pile on _reserve_.
    """

    def __init__(self, x, y, game, self_cards, **cap):
        """
        __init__(x:int, y:int, game:obj, self_cards, [offset=(0, 0),
          max_rounds:int=1, num_deal:int=1, *capability* {}]) -> None

        :cvar integer max_rounds: number of times through pile.
        :cvar integer num_deal: number of cards each pile recieves at once.
        :cvar object images: pile's base and shadow image
        :cvar object items: pile's base and shadow item
        :cvar object texts: pile's base and shadow item

        :param integer x: left x-coordinate.
        :param integer y: top y-coordinate.
        :param object game: current Game.
        :param integer self_cards: Cards dealt self at end of deal.
        :keyword tuple offset: offset from left top per card on pile.
        :keyword integer max_rounds: number of times through pile.
        :keyword integer num_deal: number of cards each pile recieves at once.

        seealso::
          Module pysollib.stackcaps with details of *capability* keywords.
        """
        super(LarasGame_Talon, self).__init__(x, y, game, **cap)
        self.__ncards = self_cards

    @property
    def _piles(self):
        """
        _piles -> tup

        :return: deal Game.s.rows[:-1]
        :rtype: tuple
        """
        return self.game.s['rows']

    @state.move_state('deal')
    def dealRow(self, rows=None, **kw):
        """
        Deal each s[rows] then deal cards for s[talon] back.

        .. dealRow([rows:seq=pile, sound:bool=False,
             flip:bool=True, reverse:bool=False, *animation keywords*]) -> int
        """
        rows = rows or self.pile
        ncards = super(LarasGame_Talon, self).dealRow(rows, **kw)
        dcards = min(self.__ncards, len(self.cards))
        self.move_pile(dcards, self.game.s['wastes'][-1], frames=kw['frames'])
        return ncards + dcards

    def dealToStacks(self, stacks, flip=True, reverse=False, frames=-1):
        """
        Deal cards to each pile with a move of some cards back on self when rank
        is position, rank is ACE, or rank is face card.

        .. dealToStacks(stacks:tup [, flip:bool=True, reverse:bool=False,
             *animation keywords*]) -> int
        """
        for i, r in enumerate(stacks):
            if not self.cards:
                return 0
            assert not self.TOPCARD.face_up
            assert r is not self
            if flip:
                self.flip_card()
            self.move_pile(1, r, frames=frames)
            rank = self.curent_rank
            if not self._dealSelf(rank == i, 1):
                return 0
            if not self._dealSelf(rank == cs.ACE, 2):
                return 0
            if not self._dealSelf(rank >= cs.JACK, 1):
                return 0
        return len(stacks)

    def _dealSelf(self, query, ncards):
        """
        _dealSelf(query:str, ncards:int) -> int | None

        Deal ncards for self when query.

        :param string query: query
        :param integer ncards: deal cards
        :return: all cards deal or not query.
        :rtype: boolean
        """
        if query:
            dcards = min(ncards, self.cards)
            self.move_pile(dcards, self.game.s['wastes'][-1])
            return dcards == ncards
        return True

    def deal_cards(self, sound=False):
        """
        deal_cards([sound:bool=False]) -> None

        Actual dealing, called from Game.talon_deal(). Deal cards back to
        last _row_ position then deal current TOPCARD.rank pile position on
        reserves.

        :keyword boolean sound: sound fx?
        """
        game = self.game
        if sound and game.can_play_sound:
            game._play_sound('deal')
        kwargs = {'frames': 3, 'shadow': 0}
        reserves = game.s['reserves']

        # return cards from reserve to row
        for reserve in reserves[:24]:
            while reserve.cards:
                reserve.move_pile(1, self._pile[game.status], **kwargs)

        # deal next card and its row to reserve
        if self.cards:
            game.status = self.curent_rank
            kw.setdefault('frames', 4)
            game._move_do(a_move.AFlipAndMoveMove(self, reserves[0], **kwargs),
                          reset=True)  # low-level
            row = self._pile[game.status]
            ncards = len(row.cards)
            while row.cards:
                for reserve in reserves[1:min(18, len(row.cards) + 1)]:
                    row.move_pile(1, reserve, **kwargs)
            num_cards = len(self.cards) or self.can_deal_cards()

        # redeal row from talon
        elif self.round < self.max_rounds:
            ncards = self._redeal(rows=self._pile, reverse=True, **kw)
            if ncards != 0:
                game._move_do(a_move.ANextRoundMove(self), reset=True)  # low level
                game.dealToRows()
            num_cards = len(self.cards)
        return num_cards

    def can_deal_cards(self):
        """
        can_deal_cards() -> bool

        Check by Game.talon_deal() if pile can deal more cards. Default is
        while there are cards available.

        :return: deal more cards?
        :rtype: True | False
        """
        return (self.cards or super(LarasGame_Talon, self).can_deal_cards())

    @property
    def currentRank(self):
        return self.TOPCARD['rank']


class DojoujisGame_Talon(LarasGame_Talon):

    @property
    def currentRank(self):
        card = self.TOPCARD
        return card['rank'] + card['deck'] * 4


class DoubleGanjifa_Talon(LarasGame_Talon):

    @property
    def currentRank(self):
        card = self.TOPCARD
        return card['rank'] + card['deck'] * 12


class HighCard_Foundation(stack.SS_Foundation):
    """
    Foundation base KING or high trump.
    """

    def __init__(self, x, y, game, **cap):
        """
        __init__(x, y, game[, offset=(0, YOFFSET), base_rank=HIGHCARD])
          -> None

        :param integer x: left x-coordinate.
        :param integer y: top y-coordinate.
        :param object game: current Game.
        :keyword tuple offset: offset from left and offset from top

        seealso::
          Module pysollib.stackcaps with details of *capability* keywords.
        """
        base_rank = cmp_cards.highestRank(game, cap['suit'])
        kwdefault(cap, base_rank=base_rank, dir=-1)
        super(HighCard_Foundation, self).__init__(x, y, game, **cap)


class Double_FoundationMethod(object):

    def __init__(self, x, y, game, **cap):
        """
        __init__(x, y, game[, offset=(0, YOFFSET), max_cards=HIGHCARD * 2,
          mod=HIGHCARD]) -> None

        :param integer x: left x-coordinate.
        :param integer y: top y-coordinate.
        :param object game: current Game.
        :keyword tuple offset: offset from left and offset from top

        seealso::
          Module pysollib.stackcaps with details of *capability* keywords.
        """
        cards = cmp_cards.highestRank(game, cap['suit']) + 1
        kwdefault(cap, max_cards=cards, mod=cards)
        super(Double_FoundationMethod, self).__init__(x, y, game, **cap)


class DoubleHighCard_Foundation(Double_FoundationMethod, HighCard_Foundation):
    pass


class Double_Foundation(Double_FoundationMethod, stack.SS_Foundation):
    pass


class LarasGame_Reserve(stack.FromRowStackBuildMethod, stack.ReserveStack):
    """
    Build any 1 card from _row_ Play top.
    """


class BridgetsGame_Reserve(LarasGame_Reserve):

    def __init__(self, x, y, game, **cap):
        cap.setdefault('base_suit', cs.TRUMP)
        super(BridgetsGame_Reserve, self).__init__(x, y, game, **cap)

    @property
    def _fromstacks(self):
        """
        Piles cards may be played from Game.s.rows after first card is played
        from Game.s.foundations.

        :param object from_stack: pile that held sequence.
        :param sequence cards: sequence.
        :return: sequence accepted?
        :rtype: boolean
        """
        if not self.cards:
            return self.game.s['foundations']
        return super(BridgetsGame_Reserve, self)._fromstacks